"""
模块化爬虫系统 - 主程序入口

使用方法:
    1. 命令行方式:
       python main.py --url "https://example.com"
       python main.py --file urls.txt
       python main.py --url "https://example.com" --config ./my_config.ini
       python main.py --url "https://example.com" --extract-links --follow-pagination
    
    2. 直接运行方式:
       python main.py
       (将使用默认配置和示例URL)
"""

import os
import sys
import time
import logging
import argparse
import configparser
from urllib.parse import urlparse

# 导入爬虫模块
from crawler.downloader import Downloader
from crawler.parser import ParserManager
from crawler.storage import Storage
from crawler.scheduler import Scheduler
from crawler.link_extractor import LinkExtractorManager
from crawler.paginator import PaginatorManager

# 确保日志目录存在
if not os.path.exists('logs'):
    os.makedirs('logs')

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('logs/crawler.log'),
        logging.StreamHandler()
    ]
)
logger = logging.getLogger('main')

def parse_args():
    """解析命令行参数"""
    parser = argparse.ArgumentParser(description='模块化爬虫系统')
    
    # URL输入方式（二选一）
    group = parser.add_mutually_exclusive_group(required=False)  # 改为不必需
    group.add_argument('--url', help='要爬取的URL')
    group.add_argument('--file', help='包含URL列表的文件路径')
    
    # 其他选项
    parser.add_argument('--config', help='配置文件路径', default='./config/config.ini')
    parser.add_argument('--depth', type=int, help='最大爬取深度', default=1)
    parser.add_argument('--timeout', type=int, help='等待所有任务完成的超时时间(秒)', default=3600)
    
    # 链接提取和翻页选项
    parser.add_argument('--extract-links', action='store_true', help='启用链接提取功能')
    parser.add_argument('--follow-pagination', action='store_true', help='启用翻页功能')
    parser.add_argument('--max-links', type=int, help='每页最大提取链接数', default=100)
    parser.add_argument('--max-pages', type=int, help='最大翻页数', default=500)
    parser.add_argument('--same-domain-only', action='store_true', help='只提取同域名链接', default=True)
    parser.add_argument('--follow-pattern', help='链接过滤正则表达式，符合的链接会被跟踪爬取')
    parser.add_argument('--exclude-pattern', help='链接排除正则表达式，符合的链接会被排除')
    
    return parser.parse_args()

def load_config(config_path):
    """加载配置文件"""
    if not os.path.exists(config_path):
        logger.error(f"配置文件不存在: {config_path}")
        sys.exit(1)
    
    config = configparser.ConfigParser()
    config.read(config_path, encoding='utf-8')
    
    # 添加命令行参数覆盖的配置
    if args.depth:
        config['DEFAULT']['max_depth'] = str(args.depth)
    
    # 添加缺失的配置项
    if 'max_depth' not in config['DEFAULT']:
        config['DEFAULT']['max_depth'] = '1'
    if 'same_domain_only' not in config['DEFAULT']:
        config['DEFAULT']['same_domain_only'] = 'True'
    
    # 添加链接提取配置
    if 'LINK_EXTRACTOR' not in config:
        config['LINK_EXTRACTOR'] = {}
    
    if args.extract_links:
        config['LINK_EXTRACTOR']['enabled'] = 'True'
    if args.max_links:
        config['LINK_EXTRACTOR']['max_links'] = str(args.max_links)
    if args.same_domain_only:
        config['LINK_EXTRACTOR']['same_domain_only'] = 'True'
    if args.follow_pattern:
        config['LINK_EXTRACTOR']['follow_pattern'] = args.follow_pattern
    if args.exclude_pattern:
        config['LINK_EXTRACTOR']['exclude_pattern'] = args.exclude_pattern
    
    # 添加翻页配置
    if 'PAGINATION' not in config:
        config['PAGINATION'] = {}
    
    if args.follow_pagination:
        config['PAGINATION']['enabled'] = 'True'
    if args.max_pages:
        config['PAGINATION']['max_pages'] = str(args.max_pages)
    
    return config

def main():
    """主函数"""
    # 解析命令行参数
    global args
    args = parse_args()
    
    # 加载配置
    config = load_config(args.config)
    
    # 创建各模块实例
    logger.info("初始化爬虫系统...")
    
    # 下载器
    downloader = Downloader(config)
    
    # 解析器管理器
    parser_manager = ParserManager(config)
    
    # 存储模块
    storage = Storage(config)
    
    # 调度器
    scheduler = Scheduler(config, downloader, parser_manager, storage)
    
    # 添加任务
    if args.url:
        logger.info(f"添加单个URL任务: {args.url}")
        scheduler.add_task(args.url)
    elif args.file:
        logger.info(f"从文件添加任务: {args.file}")
        count = scheduler.add_tasks_from_file(args.file)
        logger.info(f"成功添加 {count} 个任务")
    else:
        # 直接运行模式 - 使用示例URL
        logger.info("使用直接运行模式，添加示例URL任务")
        example_urls = [
            "https://m.findlaw.cn/case/11_1102/"
        ]
        for url in example_urls:
            scheduler.add_task(url)
        logger.info(f"成功添加 {len(example_urls)} 个示例URL任务")
        
        # 打印提示信息
        print("\n直接运行模式 - 使用示例URL:")
        for url in example_urls:
            print(f"  - {url}")
        print("\n注意: 这些是示例URL，可能无法正常访问。")
        print("如需爬取实际网站，请使用命令行参数指定URL或URL文件。")
        print("例如: python main.py --url \"https://example.com\"\n")
    
    # 显示链接提取和翻页设置
    if args.extract_links:
        logger.info("启用链接提取功能")
        print("启用链接提取功能:")
        print(f"  - 最大链接数: {args.max_links}")
        print(f"  - 只提取同域名链接: {args.same_domain_only}")
        if args.follow_pattern:
            print(f"  - 链接过滤: {args.follow_pattern}")
        if args.exclude_pattern:
            print(f"  - 链接排除: {args.exclude_pattern}")
    
    if args.follow_pagination:
        logger.info("启用翻页功能")
        print("启用翻页功能:")
        print(f"  - 最大页数: {args.max_pages}")
    
    # 启动调度器
    logger.info("启动爬虫...")
    start_time = time.time()
    scheduler.start()
    
    try:
        # 等待所有任务完成或超时
        logger.info(f"等待任务完成，超时时间: {args.timeout} 秒")
        completed = scheduler.wait_until_done(timeout=args.timeout)
        
        if completed:
            logger.info("所有任务已完成")
        else:
            logger.warning(f"等待任务超时 ({args.timeout} 秒)")
    
    except KeyboardInterrupt:
        logger.info("收到中断信号，正在停止...")
    
    finally:
        # 停止调度器
        scheduler.stop()
        
        # 关闭下载器
        downloader.close()
        
        # 打印统计信息
        stats = scheduler.get_stats()
        elapsed_time = time.time() - start_time
        
        logger.info("爬取统计:")
        logger.info(f"  总任务数: {stats['total_tasks']}")
        logger.info(f"  成功任务: {stats['successful_tasks']}")
        logger.info(f"  失败任务: {stats['failed_tasks']}")
        logger.info(f"  访问URL数: {stats['visited_urls']}")
        if args.extract_links:
            logger.info(f"  提取链接数: {stats.get('extracted_links', 0)}")
        if args.follow_pagination:
            logger.info(f"  翻页次数: {stats.get('pagination_count', 0)}")
        logger.info(f"  耗时: {elapsed_time:.2f} 秒")
        
        print("\n爬取统计:")
        print(f"  总任务数: {stats['total_tasks']}")
        print(f"  成功任务: {stats['successful_tasks']}")
        print(f"  失败任务: {stats['failed_tasks']}")
        print(f"  访问URL数: {stats['visited_urls']}")
        if args.extract_links:
            print(f"  提取链接数: {stats.get('extracted_links', 0)}")
        if args.follow_pagination:
            print(f"  翻页次数: {stats.get('pagination_count', 0)}")
        print(f"  耗时: {elapsed_time:.2f} 秒")
        
        if stats['successful_tasks'] > 0:
            data_path = os.path.abspath(config.get('DEFAULT', 'save_path', fallback='./data'))
            print(f"\n数据已保存到: {data_path}")
            
            # 如果是直接运行模式，提供更多帮助信息
            if not args.url and not args.file:
                print("\n如何查看爬取结果:")
                print("1. 打开数据目录: " + data_path)
                print("2. 按域名和日期查看JSON文件")
                print("3. 使用文本编辑器打开JSON文件查看爬取的内容")

def run_example():
    """运行示例爬虫任务"""
    print("=" * 60)
    print("模块化爬虫系统 - 示例运行")
    print("=" * 60)
    print("\n这是一个简单的爬虫示例，将爬取几个示例网站。")
    print("在实际使用中，您可以通过命令行参数指定要爬取的URL。")
    print("\n开始爬取...\n")
    
    main()

if __name__ == "__main__":
    main()
